<?php
/*
通用函数库，版本1.0
需要安装PHP的 mcrypt扩展
更新时间 2012-3-24 21:31
*/

/*
作用：检查帐号是否只包含字母数字和下划线，并且长度符合参数值规则
返回值：true/false
参数值：
$str	账号字符串
$min		字符串最小长度
$max		字符串最大长度
*/
function isAccount($str='', $min=3, $max=15) {
	if ($str=='') {
		return false;
	}
	$strLen=strlen($str);
	if ($strLen<$min || $strLen>$max) {
		return false;
	}
	$str=strtolower($str);
	$firstStr=substr($str,0,1);
	$allowStr="0123456789abcdefghijklmnopqrstuvwxyz_";
	for($i=0;$i<$strLen;$i++) {
		if(strpos($allowStr,substr($str,$i,1))===false) {
			return false;
		}
	}
	return true;
}

/*
作用：字符串加密
返回值：不定长的密文字符串，如果加密失败返回false
参数值：
$str	要加密的明文字符串
$key	密钥字符串，解密时需要提供
*/
function enCode($str='', $key='') {
	if ($str=='' || $key=='') {
		return false;
	}
	$td = mcrypt_module_open('twofish', '', 'ecb', '');
	$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
	$ks = mcrypt_enc_get_key_size($td);
	$keystr = substr(md5($key), 0, $ks);
	mcrypt_generic_init($td, $keystr, $iv);
	$encrypted = mcrypt_generic($td, $str);
	mcrypt_module_close($td);
	$hexdata = bin2hex($encrypted);
	return $hexdata;
}

/*
作用：字符串解密
返回值：解密后的明文字符串，如果解密失败返回false
参数值：
$str	要解密的密文字符串
$key	密钥字符串，加密时提供的
*/
function deCode($str='', $key='') {
	if ($str=='' || $key=='') {
		return false;
	}
	$td = mcrypt_module_open('twofish', '', 'ecb', '');
	$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
	$ks = mcrypt_enc_get_key_size($td);
	$keystr = substr(md5($key), 0, $ks);
	mcrypt_generic_init($td, $keystr, $iv);
	$encrypted = pack( "H*", $str);
	$decrypted = mdecrypt_generic($td, $encrypted);
	mcrypt_generic_deinit($td);
	mcrypt_module_close($td);
	return $decrypted;
}

/*
作用：生成指定长度的随机字符串
返回值：随机字符串，如果生成失败返回false
参数值：
$type	随机文本种子
	1	a-z的小写字母组合
	2	A-Z的大写字母组合
	3	0-9的数字组合
	4	a-z的小字母和0-9的数字组合
	5	A-Z的大字母和0-9的数字组合
	6	之前5种整合的组合
	0	按$seed_str参数值中的数组值来随机
$len	生成字符串的长度
*/
function rndStr($type=0, $len=1, $seed_str=array()) {
	switch ($type) {
		case 0:
			if (count($seed_str)==0) {
				return false;
			}
			$chars=$seed_str;
			break;
		case 1:
			$chars=array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
			break;
		case 2:
			$chars=array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
			break;
		case 3:
			$chars=array('0','1','2','3','4','5','6','7','8','9');
			break;
		case 4:
			$chars=array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9');
			break;
		case 5:
			$chars=array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9');
			break;
		case 6:
			$chars=array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9');
			break;
		default:
			return false;
			break;
	}
	$charsLen=count($chars)-1;
	shuffle($chars);
	$output='';
	for ($i=0; $i<$len; $i++) {
		$output .= $chars[mt_rand(0, $charsLen)];
	}
	return $output;
}

/*
作用：检查值是否为整数
返回值：true/false
参数值：
$str	要检查的数值
$sign	数值类型
	true 要求是正整数(不能=0，首个数字不能是0)
	false 不要求是正整数(首个数字可以是0，也可以整个数值==0)
*/
function isInt($str='', $sign=false) {
	if($str=='') {
		return false;
	}
	if ($sign==false) {
		$int='0123456789';
		$str_len=strlen($str);
		for($i=0;$i<$str_len;$i++) {
			$checkint=strpos($int,substr($str,$i,1));
			if($checkint===false) {
				return false;
			}
		}
	}
	else {
		if ($str==0 || substr($str, 0, 1)==0) {
			return false;
		}
	}
	return true;
}

/*
作用：检查字符串是否为合法的电子邮件地址
返回值：true/false
参数值：
$str	要检查的字符串
$dns	是否检查DNS中的A记录和MX记录解悉，在php 5.3 for windows之前的版本中无效
*/
function isMail($str, $dns=false) {
	$atIndex = strrpos($str, "@");
	if (is_bool($atIndex) && !$atIndex) {
		return false;
	}
	$domain = substr($str, $atIndex+1);
	$local = substr($str, 0, $atIndex);
	$localLen = strlen($local);
	$domainLen = strlen($domain);
	if ($localLen < 1 || $localLen > 64) {
		return false;
	}
	if ($domainLen < 1 || $domainLen > 255) {
		return false;
	}
	if ($local[0] == '.' || $local[$localLen-1] == '.') {
		return false;
	}
	if (preg_match('/\\.\\./', $local)) {
		return false;
	}
	if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
		return false;
	}
	if (preg_match('/\\.\\./', $domain)) {
		return false;
	}
	if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local))) {
		if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local))) {
			return false;
		}
	}
	if ($dns!=false) {
		if (!(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A"))) {
			return false;
		}
	}
	return true;
}

/*
作用：检查字符串是否是合法的IP地址规则，可包含127.0.0.1以及0.0.0.0
返回值：true/false
参数值：
$str	要检查的字符串
*/
function isIP ($str) {
	$preg='/\A((([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\.){3}(([0-9]?[0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))\Z/';
	if (preg_match($preg, $str)) {
		return true;
	}
	return false;
}

/*
作用：检查日期时间字符串是否是真实存在的一天，可判断以下日期字符串格式的有效性
	年-月-日
	年-月-日 时:分
	年-月-日 时:分:秒
返回值：true/false
参数值：
$str	要检查的字符串
*/
function isDatetime($str='') {
	if($str=='') {
		return false;
	}
	$arr=explode(' ', $str);
	$arr_count=count($arr);
	$date_str=$arr[0];
	$date=explode('-', $date_str);
	if(count($date)<>3) {
		return false;
	}
	foreach ($date as $date_str) {
		if (isInt($date_str)==false) {
			return false;
		}
	}
	if(!checkdate($date[1], $date[2], $date[0])) {
		return false;
	}
	if ($arr_count>1) {
		$time_str=$arr[1];
		$time=explode(':', $time_str);
		$time_count=count($time);
		if($time_count<>2 && $time_count<>3) {
			return false;
		}
		else {
			foreach ($time as $time_str) {
				if (isInt($time_str)==false) {
					return false;
				}
			}
			if($time[0]>23) {
				return false;
			}
			if($time[1]>59) {
				return false;
			}
			if($time_count==3) {
				if($time[2]>59) {
					return false;
				}
			}
		}
	}
	return true;
}

/*
作用：返回当前或指定月份属于第几个季度
返回值：季度整数值
参数值：
$m		指定要计算的月份，不赋值时自动获取当前月份所属的季度
*/
function quarter($m=0) {
	if (intval($m)==0) {
		$m=date('n');
	}
	if ($m>=1 && $m<=3) {
		return 1;
	}
	elseif ($m>=4 && $m<=6) {
		return 2;
	}
	elseif ($m>=7 && $m<=9) {
		return 3;
	}
	elseif ($m>=10 && $m<=12) {
		return 4;
	}
}

/*
作用：返回按UTF-8截取后的字符串，汉字和字母都当做一个字符计算
返回值：截取后的字符串
参数值：
$start	起始截取位置
$len	保留长度
*/
function substrUTF8($str='', $start=0, $len=1) {
	if ($str=='') {
		return '';
	}
	return preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$start.'}((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$len.'}).*#s', '$1', $str);
}

/*
作用：将<br>标签转为换行符（nl2br的反向函数）
返回值：字符串
参数值：
$str	要转换的字符串
*/
function br2nl($str='') {
	if ($str=='') {
		return '';
	}
	return preg_replace('/<br\\s*?\/??>/i', '', $str);
}

/*
作用：是否可以做为腾讯QQ号码，号码长度为5-15位（需配合isInt函数使用）
返回值：true/false
参数值：
$str	要判断的字符串
*/
function isQQ($str='') {
	if ($str=='') {
		return false;
	}
	$l=strlen($str);
	if($l<5|| $l>15) {
		return false;
	}
	if (isInt($str)==false) {
		return false;
	}
	if (substr($str,0,1)=='0') {
		return false;
	}
	return true;
}


/*
作用：验证昵称，长度指定，汉字不能超过8个，可以包含大小写字母，数字，下划线和减号
返回值：true/false
参数值：
$str	要判断的字符串
$min	允许最小的字符串长度
$max	允许最大的字符串长度
*/
function isNickname($str='', $min=3, $max=10) {
	if ($str=='') {
		return false;
	}
	$l=utf8_strlen($str);
	if ($l<$min || $l>$max) {
		return false;
	}
	$newStr=preg_replace('/[^\x{4e00}-\x{9fa5}]/u', '', $str);
	$chinese=mb_strlen($newStr,'utf-8'); 
	if ($chinese>8) {
		return false;
	}
	$allowStr="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
	for($i=0;$i<$l;$i++) {
		if(strpos($allowStr,substr($str,$i,1))===false && preg_match("/^[\x7f-\xff]+$/",substr($str,$i,1))==false) {
			return false;
		}
	}
	return true;
}

/*
作用：是否是指定长度的汉字，用来验证真实姓名等等，UTF8编码，每个汉字算3个字符
返回值：true/false
参数值：
$str	要判断的字符串
$min	允许最小的字符串长度
$max	允许最大的字符串长度
*/
function isChinese($str='', $min=6, $max=15) {
	if ($str=='') {
		return false;
	}
	$l=strlen($str);
	if ($l<$min || $l>$max) {
		return false;
	}
	if (preg_match("/^[\x7f-\xff]+$/",$str)==false) {
		return false;
	}
	return true;
}
	
/*
作用：是否可以做为大陆身份证号，15位身份证自动升级为18位
返回值：true/false
参数值：
$str	要判断的字符串
$strict	是否严格的检查
	true	完全按照大陆身份证号规则检查
	false	只需要长度为15或18位，并且全是数字与x字符的组合
*/
function isIdcard($str='', $strict=false) {
	if ($str=='') {
		return false;
	}
	$str_len=strlen($str);
	if ($str_len!=15 && $str_len!=18) {
		return false;
	}
	//如果是宽松检查，但不全是数字
	if ($strict==false && isInt($str, 1)==false) {
		return false;
	}
	//计算身份证校验码(新身份证最后3个字符)，根据国家标准GB 11643-1999
	function idcard_verify_number($idcard_base) {
		if (strlen($idcard_base) != 17) {
			return false;
		}
		//加权因子
		$factor=array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
		// 校验码对应值
		$verify_number_list = array('1', '0', 'X', 'x', '9', '8', '7', '6', '5', '4', '3', '2');
		$checksum = 0;
		for ($i = 0; $i < strlen($idcard_base); $i++) {
			$checksum += substr($idcard_base, $i, 1) * $factor[$i];
		}
		$mod = $checksum % 11;
		$verify_number = $verify_number_list[$mod];
		return $verify_number;
	}

	//如果是15位的身份证号，自动升级为18位
	if ($str_len==15) {
		// 如果身份证顺序码是996 997 998 999，这些是为百岁以上老人的特殊编码
		if (array_search(substr($str, 12, 3), array('996', '997', '998', '999')) !== false) {
			$str = substr($str, 0, 6) . '18'. substr($str, 6, 9);
		}
		else {
			$str = substr($str, 0, 6) . '19'. substr($str, 6, 9);
		}
		$str = $str . idcard_verify_number($str);
	}
	$str_base = substr($str, 0, 17);
	if (idcard_verify_number($str_base) != strtoupper(substr($str, 17, 1))) {
		return false;
	}
	else {
		return true;
	}
}
	
/*
作用：是否可以做为大陆手机号码，长度要求是11位并且首字符必须是1
返回值：true/false
参数值：
$str	要判断的字符串
*/
function isMobile($str='') {
	if ($str=='') {
		return false;
	}
	elseif (strlen($str)!=11 || isInt($str,1)==false || substr($str,0,1)!='1') {
		return false;
	}
	return true;
}

/*
作用：通过Javascript脚本重定向页面，可延迟并且弹出对话框
返回值：如果执行失败返回false，否则输出Javascript代码
参数值：
$url	要跳转到的目标URL
$time	延迟跳转的时间(秒)，默认为0立即跳转
$msg	跳转前要弹出的对话框内容，为空时不弹出对话框
*/
function redir($url='', $time=0, $msg='') {
	if ($url=='') {
		return false;
	}
	$time=intval($time);
	if ($time==0) {
		if ($msg=='') {
			die('<script type="text/javascript">location.href="'.$url.'"</script>');
		}
		else {
			die('<script type="text/javascript">alert("'.$msg.'");location.href="'.$url.'"</script>');
		}
	}
	else {
		if ($msg=='') {
			die('<script type="text/javascript">setTimeout(\'location.href="'.$url.'"\', '.$time.')</script>');
		}
		else {
			die('<script type="text/javascript">setTimeout(\'alert("'.$msg.'");location.href="'.$url.'"\', '.$time.')</script>');
		}
	}
}

/*
作用：计算字符串长度，在UTF8模式下汉字也只被计算成1个字符
返回值：字符串长度的整数
参数值：
$str	要检查的字符串
*/
function utf8_strlen($str='') {
	if ($str=='') {
		return 0;
	}
	$count = 0;
	$l=strlen($str);
	for($i = 0; $i < $l; $i++) {
		$value = ord($str[$i]);
		if($value > 127) {
			$count++;
            if($value >= 192 && $value <= 223) $i++;
			elseif($value >= 224 && $value <= 239) $i = $i + 2;
			elseif($value >= 240 && $value <= 247) $i = $i + 3;
		}
		$count++;
	}
	return $count;
}

/*

/*
作用：计算两个日期字符串间隔多少年/月/日
返回值：数组[0]年/[1]月/[2]日，如果执行失败则返回false
参数值：
$date1	第一个日期字符串
$date2	第二个日期字符串
*/
function diffDate($date1='',$date2='') {
	if ($date1=='' || $date2=='') {
		return false;
	}
	if(strtotime($date1) > strtotime($date2)) {
		$ymd = $date2;
		$date2 = $date1;
		$date1 = $ymd;
	}
	list($y1,$m1,$d1) = explode('-',$date1);
	list($y2,$m2,$d2) = explode('-',$date2);
	$y = $m = $d = $_m = 0;
	$math = ($y2-$y1)*12+$m2-$m1;
	$y = round($math/12);
	$m = intval($math%12);
	$d = (mktime(0,0,0,$m2,$d2,$y2) - mktime(0,0,0,$m2,$d1,$y2))/86400;
	if($d < 0) {
		$m -= 1;
		$d += date('j',mktime(0,0,0,$m2,0,$y2));
	}
	$m < 0 && $y -= 1;
	return array($y,$m,$d);
}

/*
作用：把 二维数组 中 指定键名的值 按 指定符号 拼接成字符串
返回值：字符串，如果执行失败返回false
参数值：
$split		拼接符号
$arr		二维数组
$arr_key	数组键名
*/
function arr2str($split=',', $arr=array(), $arr_key='') {
	if (count($arr)==0 || $arr_key=='') {
		return false;
	}
	$str='';
	foreach ($arr as $arr_tmp) {
		if ($str=='') {
			$str.=$arr_tmp[$arr_key];
		}
		else {
			$str.=$split.$arr_tmp[$arr_key];
		}
	}
	return $str;
}
?>